Skip to content

skip test for bug 43130 on firebird , not relevant - #170

Merged
php-pulls merged 1 commit into
php:PHP-5.3from
mariuz:issue-43130
Aug 20, 2012
Merged

php-pulls merged 1 commit into
php:PHP-5.3from
mariuz:issue-43130

Conversation

@mariuz

@mariuz mariuz commented Aug 20, 2012

Copy link
Copy Markdown
Contributor

@travisbot

Copy link
Copy Markdown

This pull request fails (merged b9a0501 into f4054af).

@mariuz

mariuz commented Aug 20, 2012

Copy link
Copy Markdown
Contributor Author

it should be merged in 5.3 branch

@php-pulls
php-pulls merged commit b9a0501 into php:PHP-5.3 Aug 20, 2012
heyJordanParker referenced this pull request in heyJordanParker/php-sharp Oct 12, 2026
Problem

Spec section 15 says `emit` raises an event and every listener for it
runs before `emit` returns. mago-sharp #170 compiles `emit e;` to
`\Sharp\Internal\emit($e);` and writes every `on` listener into
`.sharp/listeners.php`, but the engine has no `Sharp\Internal\emit`, so
an emitting method fails with "Call to undefined function".

Solution

The engine gains `Sharp\Internal\emit(object $event): void`. It finds
the `.sharp/` folder above the file that declares the event's class, as
the engine finds it for a source file, so an `extern event` in vendor/
finds its project's table. It reads the table once per request through
`zend_compile_file`, so opcache serves it, as the constant array the
file returns, without running it: code run from inside `emit` gives the
caller a symbol table a tracing-JIT frame never frees. For each event
class it keeps, for the request, the rows whose listed types the event
is an instance of, in table order. Each listener runs on a new object
of its class, created as `new` creates it, with the event when its
method takes one. An exception from a listener leaves `emit`, and the
listeners after it do not run. A missing or damaged table throws
CompileError ".sharp/listeners.php is missing or damaged. Run
vendor/bin/mago compile.".

The Mago pin moves to #170's head, so sharp/baseline/spec loses
standalone-event, extern-event, extern-event-effects and emit-forms,
and the §9.1 and §12 examples that Mago master already runs.

Files

ext/sharp/
├── sharp.stub.php     <- function Sharp\Internal\emit(object $event): void
├── sharp_arginfo.h    <- regenerated: its arginfo and ext_functions
├── sharp.c            <- emit, the table read, the per-request caches,
│                         ext_functions registered in MINIT
└── sharp_unit.h       <- SHARP_MAGO_COMMIT bb0566e, #170's head
Zend/tests/sharp/
├── OrderEvent.sharp, OrderPaid.sharp, OrderRefunded.sharp
│                      <- new: an interface and two events, one per file
├── OrderNotices.sharp, Receipts.sharp, Shipping.sharp
│                      <- new: the listeners, a private one, one without
│                         a parameter, one listed twice, one on the
│                         interface, one on an extern event, one that
│                         throws, one that emits
├── Register.sharp     <- new: raises both events with emit
├── harness/JobFailed.inc
│                      <- new: the plain PHP class the extern event marks
├── events.inc, events.phpt, events_jit_function.phpt,
│   events_jit_tracing.phpt
│                      <- new: every listener runs before emit returns,
│                         in table order, once; an exception stops the
│                         rest; a nested emit runs first; plain PHP's
│                         emit and an extern event; a TypeError; a
│                         read-only event property
└── events_table.phpt  <- new: a missing or damaged table, and a gone
                          listener class or method
sharp/baseline/spec    <- ten examples pass and leave the list
docs/architecture/slices/15-events.md
                       <- the table read, its refusals and the files
heyJordanParker referenced this pull request in heyJordanParker/php-sharp Oct 13, 2026
…t` reserved

Problem

#170's review found programs that compile and then fail, and messages that
are false:

- A `.php` write to an event's property got PHP# wording.
- `extern event` on a plain PHP interface made the interface emittable.
- A missing `{ get; set; }` interface property was reported once per hook,
  and its help offered `{ get; }` or an event parameter, which PHP refuses.
- A get-only property fit a `{ get; set; }` interface property, and PHP
  refuses to load the class.
- `emit(paid);` in a `.sharp` file was a call of a missing function, though
  spec section 2 reserves `emit`.
- The fingerprint ignored what a body emits.
- Two rows proved nothing.

Solution

- The event-write message is PHP#'s only. A `.php` file keeps master's.
- `check_extern` refuses an `extern event` on an interface, a trait or an
  enum, and `is_event_class` counts an `extern event` only on a class.
- A missing interface property is reported once. A class's help writes
  `{ get; set; }` when the interface states `set`, and an event says it
  cannot give a settable property.
- A property that is readonly, `private(set)` or get-only virtual does not
  fit one stated with `set`.
- `emit` at the start of a `.sharp` statement always raises.
- `Statement::Emit` hashes its value.
- New rows: `OrderPaid?` and `Money|OrderPaid` refused, `OrderPaid|OrderRefunded`
  accepted, `emit new Paid();` a parse error in `.php`, the `.php` writes,
  the settable rows and their compiled fix.

Files

crates/
├── analyzer/src/visibility/mod.rs            <- event-write message for `.sharp` only
├── analyzer/src/effects/check.rs             <- `extern event` marks a class
├── analyzer/src/statement/mod.rs             <- is_event_class
├── analyzer/src/statement/class_like/mod.rs  <- one report per property, settable rules
├── analyzer/tests/sharp.rs                   <- the new rows
├── syntax/src/parser/internal/emit.rs        <- `emit` always starts a statement
├── syntax/src/walker/mod.rs                  <- indentation
├── syntax/tests/sharp.rs                     <- `emit(paid)` and the `.php` row
├── fingerprint/src/statement.rs              <- Statement::Emit hashes its value
├── fingerprint/tests/signature_changes.rs    <- an emitted event change
└── sharp-bridge/tests/lower.rs               <- doc comment
heyJordanParker referenced this pull request in heyJordanParker/php-sharp Oct 13, 2026
Problem

#170's round 2 review found three listener and property messages that
were wrong or missing:

- A listener in a class whose constructor is private or protected
  compiled, and the engine then threw "Call to private
  App\Bad\Hidden::__construct()" at the first emit.
- `on int` said "Cannot find type `int`", though `int` exists and is
  not an event.
- A `{ get; private set; }` property against an interface's
  `{ get; set; }` was refused as "get-only", which it is not, and no
  row held the refusal, so the mutants job had a survivor.

Solution

`check_listener` refuses a declaring constructor that is not public:
"`Hidden`'s constructor is private, so PHP# can't create a `Hidden` to
run `heard`." `check_listed_events` says "`int` is not an event." for
every name PHP reserves for its own types, and `Any`. The unfit
property message names what the class gives: get-only, `private set`,
`protected set` or `init`.

Files

crates/analyzer/src/statement/class_like/
├── listener.rs   <- the constructor visibility refusal; BUILT_IN_TYPES
│                    and the "is not an event" arm for them
└── mod.rs        <- report_unfit_interface_property names what the
                     class gives
crates/analyzer/tests/sharp.rs
                  <- rows: private, protected and public constructors;
                     `on int, string`, `on Any`, an enum; private set,
                     protected set, a computed property, `init`
heyJordanParker referenced this pull request in heyJordanParker/php-sharp Oct 13, 2026
…rule names

Problem: #166 (Map methods and section 12 key rules) and #171 (structure rule
names) merged into master, so #170 conflicted and its CI did not run. Two
files conflicted, and master changed what a type that names no type gives
a value.

Solution: both sides kept, one shape each.

- report_undefined_types, master's loop over a type a declaration writes,
  calls this branch's report_undefined_type, which the `on` clause check
  also calls. master's known_type_or_error stays.
- statement/mod.rs keeps this branch's analyze_emit, is_event and
  is_event_class beside master's report_keys_sharing_entries, and both
  imports.
- known_type_or_error now gives a value of a type that names no type the
  error type, where it was a reference. analyze_emit skips the error type
  in place of a reference, so `emit missing;` for a parameter
  `Missing missing` adds no "`emit` takes an event, and `` is not one."
  beside the error where the type is written. No reference reaches `emit`
  any more.

crates/analyzer/src/statement/
  function_like/mod.rs   report_undefined_types calls report_undefined_type
  mod.rs                 both sides' functions; emit skips the error type
heyJordanParker referenced this pull request in heyJordanParker/php-sharp Oct 13, 2026
feat: raise events with emit and listen with on, spec section 15
heyJordanParker referenced this pull request in heyJordanParker/php-sharp Oct 13, 2026
…ame rule

Problem: #170 merged first. Its events refused `public event Print(int id);`,
`Exit` and `Empty` with "Event `Print` name cannot be a reserved keyword",
though an event is a class and a PHP-only word or a capitalized PHP#
keyword names a class. `emit` at file level said "not supported yet",
though section 27 makes any statement that runs code at file level
invalid. #170's on-clause test used a type clippy refuses, which CI never
linted because its clippy skipped test targets.

Solution: the merge keeps this branch's `check_class_name` for an event's
name, so `event Print`, `Exit` and `Empty` compile and lower to a final
class, and `event Self` is refused as a class named `Self` is. The
statement parser keeps #170's `emit` arm beside this branch's local
declaration arm, which no longer takes `list` or `function`. `emit` at
file level gets the file-level error, and the on-clause test infers its
type.

crates/
├── syntax/src/parser/internal/statement.rs    the emit arm beside the local declaration arm
├── syntax/tests/sharp.rs                      the on-clause test infers its type
├── semantics/src/internal/checker/sharp.rs    runs_code holds Emit
├── semantics/tests/sharp.rs                   events named Print, Exit and Empty compile, Self is refused;
│                                              emit at file level is a file-level statement
└── sharp-bridge/tests/lower.rs                event Print lowers to a final class
heyJordanParker referenced this pull request in heyJordanParker/php-sharp Oct 13, 2026
…arp 164ef44

#114's tests of a change after ?. on a List index need mago-sharp #176, which types that index nullable and marks it ZEND_DIM_IS. a9f1882, the pin, predates it, so mago compile refused Grid.sharp. The pull goes on to 164ef44, the merge of #176. That Mago makes event a keyword (#170), so Log.note's parameter becomes entry.

The 20 examples that Mago passes leave sharp/baseline/spec, and no example joins it.

Co-Authored-By: Claude <noreply@anthropic.com>
heyJordanParker referenced this pull request in heyJordanParker/php-sharp Oct 13, 2026
…structs keep apart

Problem: #170 added `MetadataFlags::EVENT` at `1 << 48`, the bit this branch's `STRUCT` held, so after a plain
merge every struct read as an event and every event as a struct, with no conflict to say so. This branch also writes
a struct's `init` property at its read visibility, public, which #170's interface check reads as settable, so a class
that gives an interface's `set` property with `init` stopped being refused.

Solution: keep master's `EVENT` at `1 << 48`, move `STRUCT` to `1 << 49` and `REQUIRED` to `1 << 50`, so every flag
holds its own bit. A struct emitted is refused as no event, and `==` on an event is refused as on any class, so each
row fails if the two flags ever share a bit again. #170's interface check treats an `init` property as set only while
its object is created. The other conflicts keep both sides: master's `emit`, `on`, miscased keywords and its
`list`/`function` local rule, beside the struct parser, which runs before a miscased type keyword is read, as an event
does.

crates/
├── codex/src/metadata/flags.rs               EVENT 1<<48 (master), STRUCT 1<<49, REQUIRED 1<<50
├── codex/src/scanner/function_like.rs        both sides' imports
├── analyzer/src/statement/mod.rs             master's imports, minus TObject this branch no longer uses
├── analyzer/src/statement/class_like/mod.rs  report_unfit_interface_property: an `init` property is not settable
├── analyzer/tests/sharp.rs                   emit_takes_an_event: `emit spot;` row
│                                             a_struct_compares_by_value: `==` on two `Moved` events row
├── hir/src/lower/error/mod.rs                both parse errors
└── syntax/src/
    ├── error.rs                              StructHeaderTypeInSharp beside MiscasedKeywordInSharp
    ├── cst/node.rs, walker/mod.rs            both sides' imports
    └── parser/internal/
        ├── statement.rs                      struct arm, master's emit arm and local-declaration kinds
        ├── class_like/mod.rs                 is_at_struct before read_php_type_declaration
        └── class_like/method.rs              refuse_required beside parse_optional_on
heyJordanParker referenced this pull request in heyJordanParker/php-sharp Oct 13, 2026
Problem: after the merge with #170 and #173, nightly CI's `a_property_default_of_100_000_terms_is_inferred_on_a_small_stack`
overflowed its 128 KiB thread. The parser grows the stack only at a guard, when less than the 100 KiB red zone is
left, and the frames from `parse_statement`'s guard to `parse_expression_with_precedence`'s, through a class and its
property, came to about 93 KiB in an unoptimized macOS build, with `parse_statement_inner` alone at 48 KiB. Master's
`emit` arm and this branch's struct arms each passed alone; together, on CI's larger frames, the chain passed the
space the first guard leaves. With a 80 KiB red zone on a 90 KiB thread, the same test overflows locally.

Solution: `parse_classlike_member` runs through `ensure_sufficient_stack`, as `parse_statement` does. A member is a
recursive entry point, since its body holds statements and an anonymous class's members, so the chain splits in two,
about 57 and 38 KiB. The 80 KiB red zone test passes with it. Parsing is unchanged.

crates/syntax/src/parser/internal/class_like/
└── member.rs   parse_classlike_member guards parse_classlike_member_inner, the member's former body
heyJordanParker referenced this pull request in heyJordanParker/php-sharp Oct 13, 2026
Master brings braces always, case-sensitive keywords, constructors and
file-level statements (#173), `?.` on a List index (#176), and the Map
key checks for groupBy and associateBy (#166), with #170 and #171. The
generics slice keeps its type arguments, statics, class values and
argument checks on top. 21 files conflicted, and every one keeps both
sides.

Parse type hints, locals and events with both sides' rules:
- The `.sharp` lexer keeps a keyword only in exact lowercase, so `List`,
  `Class` and `Function` lex as names. The slice's keyword-kind arms
  for them are dead and are gone. A name followed by `<` starts a
  generic hint, and a name followed by `(` starts a function hint
- A statement may start with `const`, a name or `(`, beside master's
  `emit`. A local declaration uses master's uppercase-name test
- The parse errors keep both NamedConstructorTypeParametersInSharp and
  MiscasedKeywordInSharp
- A method's type parameters live in the arena. With master's `on`
  clause, `Method` grew past clippy's large_enum_variant limit for
  ClassLikeMember, and a local's hint already lives in the arena

Check Map keys once, with the slice's class-value rule:
- A key type is a Map key by the slice's `is_map_key`, so a class value
  keys no Map. Master's groupBy and associateBy paths, its mixed
  backed-enum checks and its read-back of keys stay as master wrote them
- `get_backing_key_type`, `get_sole_backed_enum` and
  `ComparisonResult::for_dialect` take the dialect, as the slice changed
  them, at each of master's new call sites
- A groupBy or associateBy key a class value fills is refused with
  template-constraint-violation, master's code for every key position
- The bridge reads a key back through `Types::backed_enum`, and master's
  duplicate `Lowering::backed_enum` is gone

Keep master's other rules beside the slice's:
- A typed local checks its type arguments, then reports master's
  miscased keyword, then an unknown type
- A static write through a class value with type arguments goes to the
  slice's per-type-argument static, and any other write takes master's
  path
- The checker keeps its type parameter, `on` clause and get-only
  interface property rules in one message each, and drops the stale
  "a type parameter as a catch type is not supported yet"
- The name walker keeps master's `walk_in_on` and the slice's deletion
  of `walk_in_inheritance`
- A `.sharp` call into a plain PHP template bound, `Pick.pair(1, "a")`,
  is refused once by template-constraint-violation, as the slice reports
  every PHP# argument outside a bound

crates/
├── syntax/
│   ├── src/cst/cst/class_like/method.rs        type parameters in the arena
│   ├── src/error.rs                            both sides' parse errors
│   ├── src/parser/internal/
│   │   ├── class_like/method.rs                allocates a method's type parameters
│   │   ├── event.rs                            both sides' event forms
│   │   ├── local_declaration.rs                master's uppercase-name test
│   │   ├── statement.rs                        `emit`, `const`, a name or `(`
│   │   └── type_hint.rs                        a name then `<` or `(` starts a hint
│   └── tests/sharp.rs                          reads the arena type parameters
├── hir/src/lower/error/mod.rs                  lowers both parse errors
├── names/src/
│   ├── binding.rs                              passes a method's type parameters on
│   └── internal/walker.rs                      `walk_in_on`, and type parameters
├── semantics/
│   ├── src/internal/checker/sharp.rs           one message per member rule
│   └── tests/sharp.rs                          both sides' checker tests
├── analyzer/
│   ├── src/expression/
│   │   ├── assignment/array_assignment.rs      master's per-entry check by dialect
│   │   ├── call/method_call.rs                 static writes through a class value
│   │   └── instantiation.rs                    both sides' imports
│   ├── src/invocation/
│   │   ├── analyzer.rs                         both sides' argument checks
│   │   └── return_type_fetcher.rs              master's groupBy path, the slice's key test
│   ├── src/resolver/property.rs                both sides' imports
│   ├── src/statement/
│   │   ├── function_like/mod.rs                `is_map_key` with master's null reason
│   │   ├── mod.rs                              typed locals, Map keys and `emit`
│   │   └── return.rs                           both sides' imports
│   ├── src/utils/expression/array.rs           backing key type by dialect
│   └── tests/sharp.rs                          one issue per bound and key
├── orchestrator/src/service/incremental_analysis/compile.rs   both sides' tests
└── sharp-bridge/src/lower.rs                   key read-back through Types
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants